#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>		 
#include <fcntl.h>
#include <pthread.h>
#include <termios.h>
#include <errno.h>
#include "public.h"

/*
 *	abstruct : uart operation. 
 */

int uart_485 = 0;
int uart_ac = 0;
int uart_bd = 0;

/*
 * function abstruct : uart open( 0 ~ 3 ).
 * parameter illustration: 
 *		[com]: uart number;
 *      [dev]: global uart device number
 */
static int serial_open(int com, int * dev)
{
	char filename[128] ;

	if (com == 0) 	
		sprintf(filename,"/dev/ttyS0") ;
	else if (com == 1)
		#ifdef PC_DEBUG
		sprintf(filename,"/dev/ttyUSB0") ;
		#else
		sprintf(filename,"/dev/ttyS1") ;
		#endif
	else if (com == 2)
		sprintf(filename,"/dev/ttyS2") ;	
	else if (com == 3)
		sprintf(filename,"/dev/ttyS3") ;
	else if (com == 4)
		sprintf(filename,"/dev/ttyS4") ;	
	else if (com == 5)
		sprintf(filename,"/dev/ttyS5") ;
	else if (com == 6)
		sprintf(filename,"/dev/ttyS6") ;	
	else if (com == 7)
		sprintf(filename,"/dev/ttyS7") ;
	else if (com == 8)
		sprintf(filename,"/dev/ttyS8") ;
	else 
		sprintf(filename,"/dev/ttyS9") ;

	//sprintf(filename, "/dev/ttyS%d", com);

	*dev = open(filename, O_RDWR|O_NOCTTY|O_NDELAY);
	if (dev < 0) {
		perror("serial open error");
		exit(1);
	}

	/* Determine whether the state of the serial port is blocking state */
	if(fcntl(*dev, F_SETFL, 0) < 0) {
		printf("fcntl failed!\n");
	    return -1;
	}
	else {
	    printf("fcntl=%d\n",fcntl(*dev, F_SETFL,0));
	}

	isatty(STDIN_FILENO);

	printf("[%s]serial open!\n", filename);

	return 0;
}

/*
 * function abstruct : set serial Baud Rate.
 * parameter illustration: 
 *		[dev]: device number; [speed]: Baud rate
 */
static int set_speed(int dev, int speed)
{
	int i;
	int status;
	struct termios option;
	int speed_def[] = { B2000000,B921600,B576000,B500000,B460800,B230400,B115200,B38400,B19200,B9600,B4800,B2400,B1200,B300 };
    int name_def[]  = { 2000000, 921600,57600,500000,460800,230400,115200,38400,19200,9600,4800,2400,1200,300 };

	tcgetattr(dev, &option);

	for (i = 0; i < sizeof(speed_def) / sizeof(int); i++) {
		if (speed == name_def[i]) {
			tcflush(dev, TCIOFLUSH);

			cfsetispeed(& option, speed_def[i]);
			cfsetospeed(& option, speed_def[i]);
			
			status = tcsetattr(dev, TCSANOW, & option);
			if (status != 0) {
				perror("set speed fail.");
				return -1;
			}

			tcflush(dev, TCIOFLUSH);
		}
	}

	return 0;
}

/*
 * function abstruct : set serial Parity.
 * parameter illustration: 
 *		[dev]: device number; [databit]: data bit, [stopbit]: stop bit, [parity] : parity.
 */
static int set_parity(int dev, int databit, int stopbit, int parity)
{
	struct termios options;

	if (tcgetattr(dev, & options) != 0) {
		perror("set parity error");
		return -1;
	}

	cfmakeraw(&options);
	options.c_cflag |= (CLOCAL | CREAD);
	options.c_cflag &= ~CSIZE;

	/* Set data bits */
	switch (databit) {	
		case 7:
			options.c_cflag |= CS7;
			break;
		
		case 8:
			options.c_cflag |= CS8;
			break;
		
		default:
			perror("Unsupported data size.");
			return -1;
	}

	/* Set parity bits */
	switch (parity) {
		case 'n':
		case 'N':    
			options.c_cflag &= ~PARENB;		/* Clear parity enable */
			options.c_iflag &= ~INPCK;		/* Enable parity checking */ 
			break;  

		case 'o':   
		case 'O':     
			options.c_cflag |= (PARODD | PARENB); /* Set to an odd parity */  
			options.c_iflag |= INPCK;             /* Disable parity checking */ 
			break;  

		case 'e':  
		case 'E':   
			options.c_cflag |= PARENB;		/* Enable parity */    
			options.c_cflag &= ~PARODD;		/* Convert even parity */     
			options.c_iflag |= INPCK;       /* Disable parity checking */
			break;

		case 'S': 
		case 's':  /* as no parity */   
			options.c_cflag &= ~PARENB;
			options.c_cflag &= ~CSTOPB;
			break;  

		default:   
			perror("Unsupported parity.");  
			return -1;  
	}

	/* Set stop bits */  
	switch (stopbit) {   
		case 1:    
			options.c_cflag &= ~CSTOPB;  
			break;  
		case 2:    
			options.c_cflag |= CSTOPB;  
		   break;
		default:    
			 perror("Unsupported stop bits");  
			 return -1; 
	}

	/* Set input parity option */ 
	if (parity != 'n')   
		options.c_iflag |= INPCK; 

	 /* raw input */
    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    /* raw ouput */
    options.c_oflag &= ~OPOST;

	//设置流控
    //RTS/CTS (硬件) 流控制
    options.c_cflag &= ~CRTSCTS; //无流控
    //输入的 XON/XOFF 流控制
    options.c_iflag &= ~IXOFF; //不启用
    //输出的 XON/XOFF 流控制
    options.c_iflag &= ~IXON; //不启用

    // 防止0x0D变0x0A
    options.c_iflag &= ~(ICRNL | IGNCR);

    options.c_iflag &= ~(INLCR | ICRNL);
    options.c_iflag &= ~(IXON | IXOFF | IXANY); //不要软件流控制

	// options.c_cc[VTIME] = 1;	/* Set timeout 15 seconds*/   
	// options.c_cc[VMIN] = 1;		/* Update the options and do it NOW */
	// options.c_lflag &= ~ECHO; /* 关闭回终端回显功能*/

	tcflush(dev, TCIFLUSH);

	if (tcsetattr(dev, TCSANOW, & options) != 0) { 
		perror("set parity function fail.");   
		return -1;  
	}
	return 1;  
}

/*
 * receive thread
 */
void * uartac_receive_thread(void * param)
{
	int read_byte;
	unsigned char read_buf[MAX_BUFFER];

	if (uart_ac < 0)
		pthread_exit(NULL);

	printf("************************* ac pid : %d   ------> receive \n", getpid());

	while( 1 ) {
		tcflush(uart_ac, TCIOFLUSH);
		memset(read_buf, 0, sizeof(read_buf));
		read_byte = 0;

		read_byte = read(uart_ac, read_buf, MAX_BUFFER);
		if (read_byte < 0) {
			printf("read from com error, read len = %d\n", read_byte);
			break;
		}
		else {
			//printf("acread :%d:%s\n", read_byte, read_buf);
			receive_data_analy(read_byte, read_buf);
			//write_file(primitive_measurement.pm, (char *)read_buf, read_byte);				
		}	
	}

	printf("exit receive thread pid = %d\n", getpid());
	pthread_exit(NULL);
}

void * uartbd_receive_thread(void * param)
{
	int read_byte;
	unsigned char read_buf[MAX_BUFFER];

	if (uart_bd < 0)
		pthread_exit(NULL);


	printf("************************* bd pid : %d   ------> receive \n", getpid());

	while( 1 ) {
		tcflush(uart_bd, TCIOFLUSH);
		memset(read_buf, 0, sizeof(read_buf));
		read_byte = 0;

		read_byte = read(uart_bd, read_buf, MAX_BUFFER);
		if (read_byte < 0) {
			printf("read from com error, read len = %d\n", read_byte);
			break;
		}
		else {
			//printf("bdread:%d:%s\n", read_byte, read_buf);
			receive_data_analy_bd(read_byte, read_buf);
			//write_file(primitive_measurement.pm, (char *)read_buf, read_byte);
		}	
	}

	printf("exit receive thread pid = %d\n", getpid());
	pthread_exit(NULL);
}

/*
 * send thread
 */
void * uart_send_thread(void * param)
{
	printf("************************* send pid : %d   ------> send \n", getpid());

	while( 1) {			
		if ((pk.flag_ac == SEND_VALID) && (pk.flag_bd == SEND_VALID)) {
			uart485_send_to_dtu(&pk);
			
			memset(&pk, 0, sizeof(struct package));
			pk.flag_ac = 0;
			pk.flag_bd = 0;
		}
	}
	
	printf("exit send thread pid = %d\n", getpid());
	pthread_exit(NULL) ;
}

/*
 * function abstruct : uart initialization
 * parameter illustration: 
 *		[com]: uart number,[baudrate]: baud rate, [databit]: data bit
 *		[stopbit]: stop bit, [parity]: parity
 */
int uart_init(int com, int baudrate, int databit, int stopbit, char parity, int * dev)
{
	serial_open(com, dev);
	printf("uart[%d] dev is %d\n", com, *dev);

	set_speed(*dev, baudrate);

	if (set_parity(*dev, databit, stopbit, parity) == -1) {
		perror("init: set parity error");
		exit(0);
	}

	return 0;
}

void uart_exit(int dev)
{
	close(dev);
}

void uart485_send(int dev, unsigned char * data, int len)
{
	int byte = 0;

	byte = write(dev, data, len);
	printf("send:%d:%s\n", byte, data);
	//sleep(1);
}

void uart485_send_to_dtu(struct package * src)
{
	char buffer[4096];

	sprintf(buffer, 
			//"appKey=%s&deviceCode=%s&gga_1=%s&gga_2=%s&rtcm_1=%s&rtcm_2=%s&tilt=%s",
			"{\"appKey\":\"%s\",\"deviceCode\":\"%s\",\"gga_1\":\"%s\",\"gga_2\":\"%s\",\"rtcm_1\":\"%s\",\"rtcm_2\":\"%s\",\"tilt\":\"%s\"}",
			appkey,
			devicecode,
			src->gga_ac,
			src->gga_bd,
			src->rtcm_ac.transfer,
			src->rtcm_bd.transfer,
			src->angle);

	//printf("485 send buffer %d:%s\n", strlen(buffer), buffer);

	tcflush(uart_485, TCIOFLUSH);
	write(uart_485, buffer, strlen(buffer));
}

void config_6226(int dev)
{
	int i;
	const char *cmd[15] =
	{
		"$reset,0,hff\r\n"
		"$CFGPRT,1,0,115200,3,7\r\n"
		"$CFGMSG,2,0,0\r\n",
		"$CFGMSG,2,1,0\r\n",             
		"$CFGMSG,2,2,1\r\n",              
		"$CFGMSG,2,3,0\r\n",              
		"$CFGMSG,2,4,0\r\n",
		
		"$CFGMSG,0,0,0\r\n",
		"$CFGMSG,0,1,0\r\n",             
		"$CFGMSG,0,2,0\r\n",              
		"$CFGMSG,0,3,0\r\n",              
		"$CFGMSG,0,4,0\r\n",              
		"$CFGMSG,0,5,0\r\n",             
		"$CFGMSG,0,6,0\r\n",              
		"$CFGMSG,0,7,0\r\n",
		"$CFGSAVE,\r\n",
	};

	write(dev, cmd[0], strlen(cmd[0]));
	return ;
	
	for(i = 0; i < 15; i++)
	{
		write(dev, cmd[i], strlen(cmd[i]));
		usleep(1000);
	}
}

